/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "zlang_in.h"

int Keyword_switch( struct ZlangRuntime *rt )
{
	struct ZlangTokenDataUnitHeader		*switch_token_info = NULL ;
	struct ZlangTokenDataUnitHeader		*switch_begin_of_statement_segment_token_info = NULL ;
	struct ZlangInterpretStatementContext	switch_expr_interpret_statement_ctx ;
	struct ZlangInterpretStatementContext	case_expr_interpret_statement_ctx ;
	struct ZlangObject			*switch_var_obj = NULL ;
	struct ZlangObject			*case_val_obj = NULL ;
	struct ZlangObject			*logic_obj = NULL ;
	unsigned char				logic_result ;
	struct ZlangTokenDataUnitHeader		*token_info1 = NULL ;
	char					*token1 = NULL ;
	struct ZlangTokenDataUnitHeader		*token_info2 = NULL ;
	char					*token2 = NULL ;
	struct ZlangTokenDataUnitHeader		*token_info4 = NULL ;
	char					*token4 = NULL ;
	struct ZlangTokenDataUnitHeader		*token_info5 = NULL ;
	char					*token5 = NULL ;
	/*
	struct ZlangObject			*bak_in_obj = NULL ;
	*/
	struct ZlangFunction			*bak_in_func = NULL ;
	int					nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	switch_token_info = rt->travel_token_info ;
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info1 , token1 )
	if( token_info1->token_type != TOKEN_TYPE_BEGIN_OF_SUB_EXPRESSION ) /* ( */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '(' but '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	TEST_RUNTIME_DEBUG( rt )
	{
		TOKENTYPE_TO_STRING( rt->travel_token_info->token_type , _zlang_token_type_str )
		PRINT_TABS_AND_FORMAT( rt , "CALL InterpretExpression , last_token[%s][%s]" , _zlang_token_type_str , rt->travel_token )
	}
	memset( & switch_expr_interpret_statement_ctx , 0x00 , sizeof(struct ZlangInterpretStatementContext) );
	switch_expr_interpret_statement_ctx.token_of_expression_end1 = TOKEN_TYPE_END_OF_SUB_EXPRESSION ;
	nret = InterpretExpression( rt , & switch_expr_interpret_statement_ctx , & switch_var_obj ) ;
	TEST_RUNTIME_DEBUG( rt )
	{
		TOKENTYPE_TO_STRING( rt->travel_token_info->token_type , _zlang_token_type_str )
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "InterpretExpression return[%d] last_token[%s][%s] " , nret , _zlang_token_type_str , rt->travel_token ); DebugPrintObject(rt,switch_var_obj); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
	}
	if( nret != ZLANG_INFO_END_OF_EXPRESSION )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info2 , token2 )
	switch_begin_of_statement_segment_token_info = token_info2 ;
	
	rt->travel_token_datapage_header = switch_token_info->p1 ;
	rt->travel_token_dataunit = switch_token_info->p2 ;
	
_GOTO_TEST_NEXT_CASE :
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info4 , token4 )
	if( token_info4->token_type == TOKEN_TYPE_CASE )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "switch ( switch_var_obj ) { ... }" )
		
		TEST_RUNTIME_DEBUG( rt )
		{
			TOKENTYPE_TO_STRING( rt->travel_token_info->token_type , _zlang_token_type_str )
			PRINT_TABS_AND_FORMAT( rt , "CALL InterpretExpression , last_token[%s][%s]" , _zlang_token_type_str , rt->travel_token )
		}
		memset( & case_expr_interpret_statement_ctx , 0x00 , sizeof(struct ZlangInterpretStatementContext) );
		case_expr_interpret_statement_ctx.token_of_expression_end1 = TOKEN_TYPE_ANOTHER_SIDE ;
		nret = InterpretExpression( rt , & case_expr_interpret_statement_ctx , & case_val_obj ) ;
		TEST_RUNTIME_DEBUG( rt )
		{
			TOKENTYPE_TO_STRING( rt->travel_token_info->token_type , _zlang_token_type_str )
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "InterpretExpression return[%d] last_token[%s][%s] " , nret , _zlang_token_type_str , rt->travel_token ); DebugPrintObject(rt,switch_var_obj); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
		}
		if( nret != ZLANG_INFO_END_OF_EXPRESSION )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret;
		}
		
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "switch ( switch_var_obj ) { case case_val_obj: ... } - switch_var_obj " ); DebugPrintObject(rt,switch_var_obj); printf( " - case_val_obj " ); DebugPrintObject(rt,case_val_obj); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
		
		nret = Compare_EQUAL( rt , switch_var_obj , case_val_obj , & logic_obj ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "switch-case test , swich_var_obj " ); DebugPrintObject(rt,switch_var_obj); printf( " , case_valobj " ); DebugPrintObject(rt,case_val_obj); printf( " , logic_val_obj " ); DebugPrintObject(rt,logic_obj); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
		if( nret )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret;
		}
		
		nret = IsObjectTrueValue( rt , logic_obj , & logic_result ) ;
		if( nret )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , nret , "IsObjectTrueValue failed" )
			return nret;
		}
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "switch-case test , logic_result[%d]" , logic_result )
		
		if( ! logic_result )
		{
			rt->travel_token_datapage_header = token_info4->p1 ;
			rt->travel_token_dataunit = token_info4->p2 ;
			if( rt->travel_token_datapage_header == NULL )
			{
				rt->travel_token_datapage_header = switch_begin_of_statement_segment_token_info->p1 ;
				rt->travel_token_dataunit = switch_begin_of_statement_segment_token_info->p2 ;
				NEXTTOKEN( rt )
				
				TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
				return ZLANG_INFO_END_OF_STATEMENT;
			}
			else
			{
				goto _GOTO_TEST_NEXT_CASE;
			}
		}
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretStatementSegment" )
		IncreaseStackInfo( rt , NULL );
		/*
		bak_in_obj = rt->in_obj ;
		rt->in_obj = NULL ;
		*/
		bak_in_func = rt->in_func ;
		rt->in_func = NULL ;
		nret = InterpretStatementSegment( rt ) ;
		/*
		rt->in_obj = bak_in_obj ;
		*/
		rt->in_func = bak_in_func ;
		DecreaseStackInfo( rt );
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InterpretStatementSegment return[%d]" , nret )
		if( nret == ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
		{
			;
		}
		else if( nret == ZLANG_INFO_BREAK )
		{
			rt->travel_token_datapage_header = switch_begin_of_statement_segment_token_info->p1 ;
			rt->travel_token_dataunit = switch_begin_of_statement_segment_token_info->p2 ;
			NEXTTOKEN( rt )
			
			TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
			return ZLANG_INFO_END_OF_STATEMENT;
		}
		else if( nret == ZLANG_INFO_CONTINUE )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "unexpect 'continue'" )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_SYNTAX;
		}
		else
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "unexpect '%s'" , rt->travel_token )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret;
		}
	}
	else if( token_info4->token_type == TOKEN_TYPE_DEFAULT )
	{
		TRAVELTOKEN_AND_SAVEINFO( rt , token_info5 , token5 )
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretStatementSegment" )
		IncreaseStackInfo( rt , NULL );
		/*
		bak_in_obj = rt->in_obj ;
		rt->in_obj = NULL ;
		*/
		bak_in_func = rt->in_func ;
		rt->in_func = NULL ;
		nret = InterpretStatementSegment( rt ) ;
		/*
		rt->in_obj = bak_in_obj ;
		*/
		rt->in_func = bak_in_func ;
		DecreaseStackInfo( rt );
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InterpretStatementSegment return[%d]" , nret )
		if( nret == ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
		{
			;
		}
		else if( nret == ZLANG_INFO_BREAK )
		{
			rt->travel_token_datapage_header = switch_begin_of_statement_segment_token_info->p1 ;
			rt->travel_token_dataunit = switch_begin_of_statement_segment_token_info->p2 ;
			NEXTTOKEN( rt )
			
			TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
			return ZLANG_INFO_END_OF_STATEMENT;
		}
		else if( nret == ZLANG_INFO_CONTINUE )
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "unexpect 'continue'" )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_SYNTAX;
		}
		else
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "unexpect '%s'" , rt->travel_token )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret;
		}
	}
	else
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect 'case' or 'default' but '%s'" , token4 )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

int SkipStatement_switch( struct ZlangRuntime *rt )
{
	struct ZlangTokenDataUnitHeader	*token_info1 = NULL ;
	char				*token1 = NULL ;
	struct ZlangTokenDataUnitHeader	*token_info2 = NULL ;
	char				*token2 = NULL ;
	
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	PEEKTOKEN_AND_SAVEINFO( rt , token_info1 , token1 )
	if( token_info1->token_type != TOKEN_TYPE_BEGIN_OF_SUB_EXPRESSION ) /* switch ( */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "unexpect '%s'" , token1 )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	NEXTTOKEN( rt )
	
	nret = SkipExpression( rt , TOKEN_TYPE_END_OF_SUB_EXPRESSION , 0 , 0 ) ; /* switch if ( ... ) */
	if( nret != ZLANG_INFO_END_OF_EXPRESSION )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	PEEKTOKEN_AND_SAVEINFO( rt , token_info2 , token2 )
	if( token_info2->token_type == TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT )
	{
		NEXTTOKEN( rt )
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "if ( ... ) { statement_segment... }" )
		
		nret = SkipStatementSegment( rt ) ;
		if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret;
		}
	}
	else
	{
		NEXTTOKEN( rt )
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "if ( ... ) statement..." )
		
		nret = SkipStatement( rt ) ;
		if( nret != ZLANG_INFO_END_OF_STATEMENT )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret;
		}
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

int SkipStatement_case( struct ZlangRuntime *rt )
{
	int		nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	nret = SkipExpression( rt , TOKEN_TYPE_ANOTHER_SIDE , 0 , 0 ) ; /* case ... */
	if( nret != ZLANG_INFO_END_OF_EXPRESSION )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

int SkipStatement_default( struct ZlangRuntime *rt )
{
	struct ZlangTokenDataUnitHeader	*token_info1 = NULL ;
	char				*token1 = NULL ;
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info1 , token1 )
	if( token_info1->token_type != TOKEN_TYPE_ANOTHER_SIDE ) /* : */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect ':' but '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

